package com.ddstation.his_verify.service.impl;

import com.ddstation.common.service.DataDictionaryService;
import com.ddstation.common.util.CheckUtil;
import com.ddstation.crm.institution.entity.DtHealthManageInstitutionEntity;
import com.ddstation.crm.institution.mapper.DtHealthManageInstitutionMapper;
import com.ddstation.crm.outpatient.entity.DtHealthDataOutpatientMedicalEntity;
import com.ddstation.crm.outpatient.entity.DtHealthDataWestPrescriptionEntity;
import com.ddstation.crm.outpatient.mapper.DtHealthDataOutpatientMedicalMapper;
import com.ddstation.crm.outpatient.mapper.DtHealthDataWestPrescriptionMapper;
import com.ddstation.crud.entity.DtInvsIllegalAppealEntity;
import com.ddstation.crud.entity.DtInvsIllegalCheckDailyEntity;
import com.ddstation.crud.entity.DtInvsViolationManageEntity;
import com.ddstation.crud.mapper.DtInvsIllegalAppealMapper;
import com.ddstation.crud.mapper.DtInvsIllegalCheckDailyMapper;
import com.ddstation.crud.mapper.DtInvsViolationManageMapper;
import com.ddstation.crud.mapper.MaInvsViolationMessageMapper;
import com.ddstation.doctor.entity.DdDoctorEntity;
import com.ddstation.doctor.mapper.DdDoctorMapper;
import com.ddstation.drug.entity.MaInvsBaseDrug;
import com.ddstation.his_verify.entity.MaInvsIcd10SectionEntity;
import com.ddstation.his_verify.entity.MaInvsIcd10SpecialtyEntity;
import com.ddstation.his_verify.mapper.ClinicAuditItemMapper;
import com.ddstation.his_verify.model.ClinicAuditItemModel;
import com.ddstation.his_verify.service.IHisDataCheckForInvsService;
import com.ddstation.home_page.entity.DtInvsMessageQueueEntity;
import com.ddstation.home_page.mapper.DtInvsMessageQueueMapper;
import com.ddstation.home_page.mapper.HomePageMapper;
import com.ddstation.home_page.model.*;
import com.ddstation.master.entity.MaDataDictionaryEntity;
import com.ddstation.master.utils.DataDictionaryCons;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class HisDataCheckForInvsServiceImpl implements IHisDataCheckForInvsService {
    @Inject
    DtHealthDataOutpatientMedicalMapper dtHealthDataOutpatientMedicalMapper;

    @Inject
    DtHealthManageInstitutionMapper dtHealthManageInstitutionMapper;

    @Inject
    DdDoctorMapper ddDoctorMapper;

    @Inject
    DtInvsMessageQueueMapper dtInvsMessageQueueMapper;

    @Inject
    DataDictionaryService dataDictionaryService;

    @Inject
    DtInvsViolationManageMapper dtInvsViolationManageMapper;

    @Inject
    DtInvsIllegalCheckDailyMapper dtInvsIllegalCheckDailyMapper;

    @Inject
    MaInvsViolationMessageMapper maInvsViolationMessageMapper;

    @Inject
    DtHealthDataWestPrescriptionMapper dtHealthDataWestPrescriptionMapper;

    @Inject
    ClinicAuditItemMapper clinicAuditItemMapper;

    @Inject
    DtInvsIllegalAppealMapper dtInvsIllegalAppealMapper;


    private static final Logger logger = LoggerFactory.getLogger(HisDataCheckForInvsServiceImpl.class);

  //处方 OR 药品 类型 20：西药
    public static final int PRESCRIPTION_TYPE_WEST = 20;

    @Override
    public void checkHisPrescriptionsMethod(String startTime, String endTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");
        Date startDate = sdf.parse(startTime);
        Date endDate = sdf.parse(endTime);

        List<DtHealthDataOutpatientMedicalEntity> dtHealthDataOutpatientMedicalEntityList = dtHealthDataOutpatientMedicalMapper.selectByTime(startTime, endTime);
        for (DtHealthDataOutpatientMedicalEntity medical : dtHealthDataOutpatientMedicalEntityList) {
            DtHealthManageInstitutionEntity institution = dtHealthManageInstitutionMapper.selectByInstitutionIdForInvs(medical.getInstitutionId());
            String medicalId = medical.getId();
            // 智能审方开关
            if (institution.getUnderInvs() == 0) {
                continue;
            }
            DdDoctorEntity doctor = ddDoctorMapper.selectDoctorInfo(medical.getDoctorId());
            //获取当前患者当前病历下所有处方信息
            DtHealthDataWestPrescriptionEntity dtHealthDataWestPrescriptionEntity=new DtHealthDataWestPrescriptionEntity();
            dtHealthDataWestPrescriptionEntity.setMedicalId(medicalId);
            List<DtHealthDataWestPrescriptionEntity> prescriptions=dtHealthDataWestPrescriptionMapper.select(dtHealthDataWestPrescriptionEntity);

            // 旧的消息队列状态更新成不显示
            List<String> targetIds = new ArrayList<>();
            targetIds.add(medicalId);
            int updateCount = dtInvsMessageQueueMapper.updateQueueStatus(medical.getInstitutionId(), 401, 1, targetIds);
            // 新生成消息队列(用于首页地图展示)
            insertMessageQueue(medical, null);
           // 审核病历诊断
            auditOutpatientMedical(medical, institution, doctor);

            // 审核病历处方
            auditPrescriptions(medical, institution, doctor, prescriptions);

            List<DtInvsViolationManageEntity> violations = dtInvsViolationManageMapper.selectList(medical.getInstitutionId(), medicalId, null);
        }

    }

    @Override
    @Transactional(rollbackFor=Exception.class)
    public void auditOutpatientMedical(DtHealthDataOutpatientMedicalEntity medical
            , DtHealthManageInstitutionEntity institution
            , DdDoctorEntity doctor) {

        // 医疗机构诊疗执业许可证诊疗科目
        String technicalOffices = institution.getTechnicalOffices();
        // 医师执业证书执业范围
        String scopePractice = doctor.getScopePractice();
        // 医师身份证号码
        String idCard = doctor.getIdCard();
        if (!CheckUtil.isEmpty(technicalOffices)&&!CheckUtil.isEmpty(scopePractice)&&!CheckUtil.isEmpty(idCard)) {
        List<DtInvsViolationManageEntity> violations = new ArrayList<>();
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        if ((technicalOffices.indexOf("50") == -1 // 50:中医科
                && technicalOffices.indexOf("52") == -1 // 52:中西医结合科
                && technicalOffices.indexOf("02") == -1) // 02:全科医疗科
                || technicalOffices.indexOf(".02") > 0) {
            // 审核病历诊断:医疗机构超范围诊疗
            violation = auditOutpatientMedical(medical, technicalOffices);
            if (!CheckUtil.isEmpty(violation)) {
                violation.setMsgId("810001");
                // 格式化病历诊断违规内容
                formatViolationMsg(medical, violation);
                violations.add(copy(violation));
            }
        }
        // 审核病历诊断:医师超范围开具处方
        List<MaDataDictionaryEntity> scopePracticeList =  dataDictionaryService.getCodeList(DataDictionaryCons.CODE_SCOPE_PRACTICE);
        // 执业范围对应诊疗科目
        List<MaDataDictionaryEntity> filterList = scopePracticeList.stream().filter(a -> a.getValue().equals(scopePractice)).collect(Collectors.toList());
        if (filterList != null && filterList.size() > 0) {
            String scopePractices = ((MaDataDictionaryEntity)filterList.get(0)).getData1();
            if ((scopePractices.indexOf("50") == -1 // 50:中医科
                    && scopePractices.indexOf("52") == -1 // 52:中西医结合科
                    && scopePractices.indexOf("02") == -1) // 02:全科医疗科
                    || scopePractices.indexOf(".02") > 0) {
                violation = auditOutpatientMedical(medical, scopePractices);
                if (!CheckUtil.isEmpty(violation)) {
                    violation.setMsgId("810002");
                    violation.setDepartment(((MaDataDictionaryEntity) filterList.get(0)).getFullName());
                    violation.setDoctorName(doctor.getName());
                    // 格式化病历诊断违规内容
                    formatViolationMsg(medical, violation);
                    violations.add(copy(violation));
                }
            }
        } else {
            throw new RuntimeException("ma_data_dictionary表中无执业范围["+scopePractice+"]数据，请设置！");
        }

        // 审核病历诊断:多个执业地点同时开具处方
        violation = multiPractice(medical, idCard);
        if (!CheckUtil.isEmpty(violation)) {
            violation.setMsgId("810003");
            violation.setDoctorName(doctor.getName());
            violation.setParams(institution.getName() + "、" + violation.getParams());
            // 格式化病历诊断违规内容
            formatViolationMsg(medical, violation);
            violations.add(copy(violation));
        }

        // 更新病历诊断违规内容
        replaceMedicalViolation(medical, violations);
        }
    }


    @Override
    @Transactional(rollbackFor=Exception.class)
    public void auditPrescriptions(DtHealthDataOutpatientMedicalEntity medical
            , DtHealthManageInstitutionEntity institution
            , DdDoctorEntity doctor
            , List<DtHealthDataWestPrescriptionEntity> prescriptions) {
        // 诊所科室(诊疗科目)
        String technicalOffices= institution.getTechnicalOffices();
        // 医师职称
        String technicalTitle = doctor.getTechnicalTitle();
        if (!CheckUtil.isEmpty(technicalTitle)) {

        List<DtInvsViolationManageEntity> violations = new ArrayList<>();
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        int i = 0;

        // 处方单上的药品
        List<ClinicAuditItemModel> items = clinicAuditItemMapper.selectItemsByPrescriptions(prescriptions);
        logger.debug("处方单上的药品:"+ com.alibaba.fastjson.JSONObject.toJSONString(items));
        // 核心药品库至少匹配到一条
        if (items != null && items.size() > 0) {

            // 审核病历处方:无处方权开具处方、执业助理医师开具处方
            violation = rightToPrescription(doctor, items);
            if (!CheckUtil.isEmpty(violation)) {
                // 格式化病历处方违规内容
                formatViolationMsg(medical, violation);
                violations.add(copy(violation));
            }

            // 口腔诊所拔牙开具表面麻醉剂，不需要精麻资质
            if (technicalOffices.indexOf("12") == -1) { // 12:口腔科
                // 审核病历处方:未经批准开具精麻药品
                violation = rightToAnesthetic(doctor, items);
            }

            if (!CheckUtil.isEmpty(violation)) {
                // 格式化病历处方违规内容
                formatViolationMsg(medical, violation);
                violations.add(copy(violation));
            }

            // 审核病历处方:未经培训合格(未经核准)开具抗菌药物
            violation = rightToAntibiosis(doctor, items);
            if (!CheckUtil.isEmpty(violation)) {
                // 格式化病历处方违规内容
                formatViolationMsg(medical, violation);
                violations.add(copy(violation));
            }

            // 审核病历处方:越级使用抗菌药物
            violation = rightToAntibiosisGrade(doctor, items);
            if (!CheckUtil.isEmpty(violation)) {
                // 格式化病历处方违规内容
                formatViolationMsg(medical, violation);
                violations.add(copy(violation));
            }

            List<DtInvsViolationManageEntity> tempViolations = new ArrayList<>();
            // 审核病历处方:限制使用性别
            tempViolations = limitGender(items, medical.getGender());
            if (tempViolations != null && tempViolations.size() > 0) {
                for (DtInvsViolationManageEntity entity : tempViolations) {
                    // 格式化病历处方违规内容
                    formatViolationMsg(medical, entity);
                }
                violations.addAll(copys(tempViolations));
            }

            // 审核病历处方:儿童禁用
            tempViolations = childForbid(items, medical.getAge());
            if (tempViolations != null && tempViolations.size() > 0) {
                for (DtInvsViolationManageEntity entity : tempViolations) {
                    // 格式化病历处方违规内容
                    formatViolationMsg(medical, entity);
                }
                violations.addAll(copys(tempViolations));
            }

            // 审核病历处方:老年禁用
            tempViolations = oldForbid(items, medical.getAge());
            if (tempViolations != null && tempViolations.size() > 0) {
                for (DtInvsViolationManageEntity entity : tempViolations) {
                    // 格式化病历处方违规内容
                    formatViolationMsg(medical, entity);
                }
                violations.addAll(copys(tempViolations));
            }

            // 审核病历处方:超剂量不合理用药
            tempViolations = overDosage(items);
            if (tempViolations != null && tempViolations.size() > 0) {
                for (DtInvsViolationManageEntity entity : tempViolations) {
                    // 格式化病历处方违规内容
                    formatViolationMsg(medical, entity);
                }
                violations.addAll(copys(tempViolations));
            }
        }

        // 更新病历处方违规内容
        replacePrescriptionViolation(medical, prescriptions, violations);
        }

    }


    /**
     * 新生成消息队列
     */
    private void insertMessageQueue(DtHealthDataOutpatientMedicalEntity medical,
                                    List<DtInvsViolationManageEntity> violations) {
        List<DtInvsMessageQueueEntity> queues = new ArrayList<>();
        if (violations == null || violations.size() == 0) {
            DtInvsMessageQueueEntity queue = new DtInvsMessageQueueEntity();
            queue.setActionTm(new Date()); // 时间
            queue.setInstitutionId(medical.getInstitutionId()); // 机构ID
            queue.setSource(2); // 1：用户 2：系统
            queue.setBusinessSubType(401); // 业务子分类 401：处方
            queue.setFunctionKey(1); // 功能  1:登记  2：申诉
            queue.setMessageType(1); // 消息类型： 1：info 2:warning 3:error
            queue.setTargetId(medical.getId()); // 门诊病历表dt_health_data_outpatient_medical.id
            queues.add(queue);
        } else {
            for (DtInvsViolationManageEntity violation : violations) {
                DtInvsMessageQueueEntity queue = new DtInvsMessageQueueEntity();
                queue.setActionTm(violation.getViolateTm()); // 时间
                queue.setInstitutionId(medical.getInstitutionId()); // 机构ID
                queue.setSource(2); // 1：用户 2：系统
                queue.setBusinessSubType(401); // 业务子分类 401：处方
                queue.setFunctionKey(1); // 功能  1:登记  2：申诉
                queue.setMessageType(3); // 消息类型： 1：info 2:warning 3:error
                queue.setTargetId(violation.getId().toString()); // 处方违规内容管理表dt_invs_violation_manage.id
                queues.add(queue);
            }
        }
        int insertCount = dtInvsMessageQueueMapper.insertMessageQueue(queues);
    }

    /**
     *
     * 审核病历诊断
     *
     */
    private DtInvsViolationManageEntity auditOutpatientMedical(DtHealthDataOutpatientMedicalEntity medical,
                                                               String technicalOffices) {
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        List<String> technicals = new ArrayList<>();
        if (!CheckUtil.isEmpty(technicalOffices)) {
            technicals = Arrays.asList(technicalOffices.split(","));
        }

        // 没有先保存病历诊断
        if (CheckUtil.isEmpty(medical.getDiagnosis()) || CheckUtil.isEmpty(medical.getDiagnosisIcd10())) {
            return null;
        }

        List<String> icd10Codes = Arrays.asList(medical.getDiagnosisIcd10().split(","));
        List<String> diseases =  Arrays.asList(medical.getDiagnosis().split(","));

        // 直接输入的诊断没有对应的ICD10疾病编码
        if (icd10Codes.size() != diseases.size()) {
            return null;
        }

        List<MaInvsIcd10SectionEntity> notExists = new ArrayList<>();

        for (int i = 0; i < icd10Codes.size(); i++) {
            if (i >0) break; // 只对主诊断进行是否超范围校验
            Map<String, Object> param = new HashMap<String, Object>();
            List<String> icd10s = new ArrayList<>();
            icd10s.add(icd10Codes.get(i));
            param.put("icd10s", icd10s);
            List<MaInvsIcd10SectionEntity> sectionList = dtInvsIllegalCheckDailyMapper.selectTechnicalsByIcd10(param);
            if (sectionList != null && sectionList.size() > 0) {
                MaInvsIcd10SectionEntity section = sectionList.get(0);
                List<String> options = Arrays.asList(section.getOptionAll().split(","));

                // 连二级诊疗科目一起判断是否有交集
                if(getIntersection(technicals, options).size() > 0) {
                    continue;
                }

                // 去掉二级诊疗科目后判断是否有交集
                for (String option : options) {
                    Collections.replaceAll(options, option, option.split("\\.")[0]);
                }
                if (getIntersection(technicals, options).size() > 0) {
                    continue;
                }

                // icd10Codes、diseases的长度需一致，否则报错
                // 里面icd10编码和疾病顺序也需一致
                section.setDisease((String)diseases.get(i));
                notExists.add(section);
            }
        }

        if (notExists.size() > 0) {
            // 医疗机构诊疗科目名录2012版(基础表数据)
            List<MaInvsIcd10SpecialtyEntity> specialtys = dtInvsIllegalCheckDailyMapper.selectAllSpecialtys();

            String param = "";
            for (MaInvsIcd10SectionEntity section : notExists) {
                String str = ""; // 诊疗科目范围外科室或专业名称
                List<String> options = Arrays.asList(section.getOptionAll().split(","));
                for (String option : options) {
                    String name = "";
                    if (option.indexOf(".") > 0) {
                        List<MaInvsIcd10SpecialtyEntity> filterList = specialtys.stream().filter(a -> a.getSecondCode().equals(option)).collect(Collectors.toList());
                        if (filterList != null && filterList.size() > 0) {
                            name = ((MaInvsIcd10SpecialtyEntity)filterList.get(0)).getFirstName()
                                    + "."
                                    + ((MaInvsIcd10SpecialtyEntity)filterList.get(0)).getSecondName();
                        }
                    } else {
                        List<MaInvsIcd10SpecialtyEntity> filterList = specialtys.stream().filter(a -> a.getFirstCode().equals(option)).collect(Collectors.toList());
                        if (filterList != null && filterList.size() > 0) {
                            name = ((MaInvsIcd10SpecialtyEntity)filterList.get(0)).getFirstName();
                        }
                    }
                    if (CheckUtil.isEmpty(str)) {
                        str = name;
                    } else {
                        str = str + '或' + name;
                    }
                }
                str = section.getDisease() + "(" + str + ")";
                if (CheckUtil.isEmpty(param)) {
                    param = str;
                } else {
                    param = param + "、" + str;
                }
            }
            violation.setParams(param);
            return violation;
        }

        return null;
    }

    /**
     *
     * 格式化病历诊断或病历处方违规内容
     *
     */
    private DtInvsViolationManageEntity formatViolationMsg(DtHealthDataOutpatientMedicalEntity medical,
                                                           DtInvsViolationManageEntity violation) {
        String msgId = violation.getMsgId();
        String msg = "";
        JSONObject jsonBean = new JSONObject();

        if (msgId.equals("810001")) {
            // e.g. 病历诊断腹腔妊娠(妇产科)，超出核准登记诊疗科目开展诊疗活动。
            // 病历诊断{1}，超出核准登记诊疗科目开展诊疗活动。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getParams()+"\"}");

        } else if (msgId.equals("810002")) {
            // e.g. 病历诊断腹腔妊娠(妇产科)，儿科医师葫芦红超执业范围开具处方。
            // 病历诊断{1}，{2}医师{3}超执业范围开具处方。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getParams()+
                    "\",\"p2\":\""+violation.getDepartment()+
                    "\",\"p3\":\""+violation.getDoctorName()+"\"}");

        } else if (msgId.equals("810003")) {
            // e.g. 医师葫芦红在多个执业地点临安虚拟A诊所、临安虚拟B诊所同时开具处方。
            // 医师{1}在多个执业地点{2}同时开具处方。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getDoctorName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("820001")) {
            // e.g. 无处方权医师葫芦红(理疗师)开具处方。
            // 无处方权医生{1}开具处方。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getDoctorName()+
                    violation.getParams()+"\"}");
        } else if (msgId.equals("820002")) {
            // e.g. 执业助理医师葫芦红单独开具处方。
            // 执业助理医师{1}单独开具处方。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getDoctorName()+"\"}");
        } else if (msgId.equals("820003")) {
            // e.g. 医师葫芦红未经批准开具精麻药品双氢可待因片。
            // 医师{1}未经批准开具精麻药品{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getDoctorName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("820004")) {
            // e.g. 医师葫芦红未经培训合格(未经核准)开具抗菌药物头孢丙烯。
            // 医师{1}未经培训合格(未经核准)开具抗菌药物{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getDoctorName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("820005")) {
            // e.g. 医师葫芦红越级使用限制级抗菌药物头孢丙烯。
            // 医师{1}越级使用{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getDoctorName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("840004")) {
            // e.g. 阿莫西林胶囊：超剂量用药。单次最大用量2片。
            // {1}：超剂量用药。最大用量{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getItemName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("840005")) {
            // e.g. 醋酸甲羟孕酮片：仅限女性。
            // {1}：{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getItemName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("840007")) {
            // e.g. 复方风湿宁片：儿童禁用。
            // {1}：{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getItemName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        } else if (msgId.equals("840008")) {
            // e.g. 兰索拉唑：老年患者禁用。
            // {1}：{2}。
            jsonBean = JSONObject.fromObject("{\"p1\":\""+violation.getItemName()+
                    "\",\"p2\":\""+violation.getParams()+"\"}");
        }

        msg = getMsg(jsonBean, msgId);

        BeanUtils.copyProperties(medical, violation);
        violation.setMedicalId(medical.getId()); // 门诊编号
        violation.setIcd10Code(medical.getDiagnosisIcd10()); // ICD10疾病编码
        violation.setDisease(medical.getDiagnosis()); // 诊断疾病
        violation.setMsgId(msgId); // 处方违规行为提醒消息Id
        violation.setMsgTxt(msg); // 处方违规行为提醒消息
        violation.setViolateTm(new Date()); // 处方违规时间
        violation.setViolateDt(new Date()); // 处方违规日期

        return violation;
    }

    /**
     *
     * 复制单条处方违规内容
     *
     */
    private DtInvsViolationManageEntity copy(DtInvsViolationManageEntity orig) {
        DtInvsViolationManageEntity dest = new DtInvsViolationManageEntity();
        try {
            org.apache.commons.beanutils.BeanUtils.copyProperties(dest, orig);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
        return dest;
    }

    /**
     *
     * 遍历同一个医生在不同执业地点同时开处方的机构名
     *
     */
    private DtInvsViolationManageEntity multiPractice(DtHealthDataOutpatientMedicalEntity medical, String idCard) {
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        Integer val = 2; // 间隔时间为至少2小时以上
        List<Map<String,Object>> sameList = dtHealthDataOutpatientMedicalMapper.selectSameDoctorMedical(medical.getInstitutionId(), idCard, val);
        if (sameList.size() > 0 ) {
            String param = "";
            for (Map<String,Object> map : sameList) {
                String str = (String)map.get("institutionName");
                if (CheckUtil.isEmpty(param)) {
                    param = str;
                } else {
                    param = param + "、" + str;
                }
            }
            violation.setParams(param);
            return violation;
        }

        return null;
    }

    /**
     *
     * 更新病历诊断违规内容
     * 先删除再重新生成
     */
    private void replaceMedicalViolation(DtHealthDataOutpatientMedicalEntity medical,
                                         List<DtInvsViolationManageEntity> violations) {
        DtInvsViolationManageEntity dtInvsVidolationManageEntity = new DtInvsViolationManageEntity();
        dtInvsVidolationManageEntity.setInstitutionId(medical.getInstitutionId());
        dtInvsVidolationManageEntity.setMedicalId(medical.getId());
        // 旧的消息队列状态更新成不显示
        List<String> targetIds = dtInvsViolationManageMapper.selectTargetIds(dtInvsVidolationManageEntity);
        if (targetIds.size() > 0) {
            dtInvsMessageQueueMapper.updateQueueStatus(medical.getInstitutionId(), 401, 3, targetIds);
            // 旧的异常行为每日check更新成已删除
            List<String> illegalIds = dtInvsIllegalCheckDailyMapper.selectIllegalIds(medical.getInstitutionId(), 40, 401, targetIds);
            dtInvsIllegalCheckDailyMapper.updateCheckDailyStatus(medical.getInstitutionId(), 40, 401, targetIds);
            // 旧的机构异常行为申诉更新成已删除
            if (illegalIds.size() > 0) {
                dtInvsIllegalCheckDailyMapper.updateIllegalAppealStatus(illegalIds);
            }
        }
        // 旧的违规内容状态更新成已删除
        dtInvsViolationManageMapper.updateStatus(dtInvsVidolationManageEntity);
        // 新生成违规内容
        if (violations.size() > 0) {
            dtInvsViolationManageMapper.insertMedicalViolation(violations);
            // 新生成消息队列(用于首页地图展示)
            insertMessageQueue(medical, violations);
            // 新生成机构异常行为每日check
            List<DtInvsIllegalCheckDailyEntity> dailys = insertCheckDaily(medical, violations);
            // 生成新的机构异常行为申诉
            insertIllegalAppeal(dailys);
        }

    }

    /**
     *
     * 新生成机构异常行为每日check
     *
     */
    private List<DtInvsIllegalCheckDailyEntity> insertCheckDaily(DtHealthDataOutpatientMedicalEntity medical,
                                                                 List<DtInvsViolationManageEntity> violations) {
        List<DtInvsIllegalCheckDailyEntity> dailys = new ArrayList<>();
        for (DtInvsViolationManageEntity violation : violations) {
            DtInvsIllegalCheckDailyEntity daily = new DtInvsIllegalCheckDailyEntity();
            daily.setInstitutionId(medical.getInstitutionId()); // 机构ID
            daily.setCheckDt(violation.getViolateTm()); // 检查日期
            daily.setBusinessType(40); // 业务分类 40：处方违规
            daily.setBusinessSubType(401); // 业务子分类 401：处方
            daily.setTargetId(violation.getId()); // 处方违规内容管理表dt_invs_violation_manage.id
            daily.setCheckSt(-1); // 检查状态 0：正常  -1：异常  更新途径：定时钟 及 卫监人员手工更新
            daily.setMsgId(violation.getMsgId()); // 处方违规提醒消息ID dt_invs_violation_manage.msg_id
            daily.setMessage(violation.getMsgTxt()); // 处方违规行为提醒消息
            dailys.add(daily);
        }
        dtInvsIllegalCheckDailyMapper.insertCheckDaily(dailys);
        return dailys;
    }

    /**
     *
     * 新生成机构异常行为申诉
     *
     */
    private void insertIllegalAppeal(List<DtInvsIllegalCheckDailyEntity> dailys) {
        List<DtInvsIllegalAppealEntity> appeals = new ArrayList<>();
        for (DtInvsIllegalCheckDailyEntity daily : dailys) {
            DtInvsIllegalAppealEntity appeal = new DtInvsIllegalAppealEntity();
            appeal.setIllegalId(daily.getId()); // dt_invs_illegal_check_daily.id
            appeal.setAppealSt(0); // 申诉状态  0：未申诉  1：申诉中  -1：被驳回 2：申诉成功 10：关闭
            appeal.setMessageSendSt(Short.parseShort("1")); // 0:未发送 1：已发送
            appeals.add(appeal);
        }
        dtInvsIllegalCheckDailyMapper.insertIllegalAppeal(appeals);
    }

    /**
     *
     * 判断两个list是否有交集
     *
     */
    private List<String> getIntersection(List<String> list1,
                                         List<String> list2) {
        List<String> result = new ArrayList<>();
        for (String str : list2) {//遍历list1
            if (list1.contains(str)) {//如果存在这个值
                result.add(str);//放进一个list里面，这个list就是交集
            }
        }
        return result;
    }

    /**
     *
     * 取得消息内容
     *
     */
    private String getMsg(JSONObject jsonBean, String msgId) {
        String msg;
        msg = maInvsViolationMessageMapper.selectMsg(msgId);
        @SuppressWarnings("unchecked")
        Iterator<Object> iterator = jsonBean.keys();
        while(iterator.hasNext()){
            String key = iterator.next().toString();
            String sObj = jsonBean.getString(key);
            if (key.startsWith("p")) {
                key = key.replace("p", "");
            }
            msg = msg.replace("{"+key+"}", sObj);
        }
        return msg;
    }

    /**
     *
     * 判断医师是否有处方权
     *
     */
    private DtInvsViolationManageEntity rightToPrescription(DdDoctorEntity doctor, List<ClinicAuditItemModel> items) {
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        // 医师职称
        String technicalTitle = doctor.getTechnicalTitle();
        List<MaDataDictionaryEntity> technicalTitleList =  dataDictionaryService.getCodeList(DataDictionaryCons.CODE_TECHNICAL_TITLE);
        List<MaDataDictionaryEntity> filterList = technicalTitleList.stream().filter(a -> a.getValue().equals(technicalTitle)).collect(Collectors.toList());
        if (filterList != null && filterList.size() > 0) {
            if (items.size() > 0 ) {
                MaDataDictionaryEntity technical = (MaDataDictionaryEntity)filterList.get(0);
                int val  = Integer.parseInt(technical.getValue());
                if (val > 5) { // 职称级别在助理医师以下
                    String param = "(" + technical.getFullName() + ")"; // 职称名
                    violation.setParams(param);
                    violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                    violation.setDoctorName(doctor.getName());
                    violation.setMsgId("820001");
                    return violation;
                } else if (val > 4) { // 职称级别在医师以下
                    violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                    violation.setDoctorName(doctor.getName());
                    violation.setMsgId("820002");
                    return violation;
                }
            }

        } else {
            throw new RuntimeException("ma_data_dictionary表中无职称["+technicalTitle+"]数据，请设置！");
        }

        return null;
    }

    /**
     *
     * 判断医师是否有精麻药品处方权
     *
     */
    private DtInvsViolationManageEntity rightToAnesthetic(DdDoctorEntity doctor, List<ClinicAuditItemModel> items) {
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        // 麻醉药品和第一类精神药品处方资格
        Integer anestheticAuthority = doctor.getAnestheticAuthority();
        List<ClinicAuditItemModel> filterList = items.stream().filter(a -> a.getBaseDrug().getAnestheticFlg() == 1).collect(Collectors.toList());
        if (filterList != null && filterList.size() > 0) {
            if (anestheticAuthority == null || anestheticAuthority.intValue() != 1 ) {
                String param = "";
                for (ClinicAuditItemModel item : filterList) {
                    String name = item.getWestItem().getItemName(); // 精麻药品名
                    if (CheckUtil.isEmpty(param)) {
                        param = name;
                    } else {
                        param = param + "、" + name;
                    }
                }
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setDoctorName(doctor.getName());
                violation.setMsgId("820003");
                return violation;
            }
        }

        return null;
    }

    /**
     *
     * 判断医师是否有抗菌药物处方权
     *
     */
    private DtInvsViolationManageEntity rightToAntibiosis(DdDoctorEntity doctor, List<ClinicAuditItemModel> items) {
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        // 抗菌药物处方资格
        Integer antibiosisAuthority = doctor.getAntibiosisAuthority();
        List<ClinicAuditItemModel> filterList = items.stream().filter(a -> a.getBaseDrug().getAntibiosisFlg() > 0).collect(Collectors.toList());
        if (filterList != null && filterList.size() > 0) {
            if (antibiosisAuthority == null || antibiosisAuthority.intValue() < 1 ) {
                List<MaDataDictionaryEntity> antibiosisFlgList =  dataDictionaryService.getCodeList(DataDictionaryCons.CODE_ANTIBIOSIS_FLG);
                String param = "";
                for (ClinicAuditItemModel item : filterList) {
                    MaInvsBaseDrug baseDrug = item.getBaseDrug();
                    DtHealthDataWestPrescriptionEntity westItem = item.getWestItem();
                    List<MaDataDictionaryEntity> flgList = antibiosisFlgList.stream().filter(a -> a.getValue().equals(baseDrug.getAntibiosisFlg().toString())).collect(Collectors.toList());
                    String name = getAntibiosisName(flgList, westItem, baseDrug);
                    if (CheckUtil.isEmpty(param)) {
                        param = name;
                    } else {
                        param = param + "、" + name;
                    }
                }
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setDoctorName(doctor.getName());
                violation.setMsgId("820004");
                return violation;
            }
        }

        return null;
    }

    /**
     *
     * 判断是否超剂量用药
     *
     */
    private List<DtInvsViolationManageEntity> overDosage(List<ClinicAuditItemModel> items) {
        List<DtInvsViolationManageEntity> violations = new ArrayList<>();

        for (ClinicAuditItemModel item : items) {
            DtHealthDataWestPrescriptionEntity westItem = item.getWestItem();
            MaInvsBaseDrug baseDrug = item.getBaseDrug();
            // 处方剂量
            BigDecimal onceDose = new BigDecimal(((Number)westItem.getOnceDose()).toString());
            // 核心药品表最大用量
            BigDecimal maxQuantity = baseDrug.getMaxQuantity();
            if (onceDose == null || maxQuantity == null) {
                continue;
            }
            // 如果是按制剂单位开的话，需要转换成剂量单位   add by zxb 2020.3.25   start -------------------------------
            if ( westItem.getOnceDoseUnitType() != null && westItem.getOnceDoseUnitType().intValue() == 1){
                // 基础表中含量规格没有存的情况下,退出
                if ( baseDrug.getContentSpec() == null ){
                    continue;
                }
                // 根据制剂单位转化成剂量单位
                onceDose = onceDose.multiply(baseDrug.getContentSpec());
            } //add by zxb 2020.3.25   end -------------------------------

            // 处方剂量超出核心药品表最大用量
            if (maxQuantity.compareTo(onceDose) == -1) {
                String param = maxQuantity + baseDrug.getContentUnitText();
                DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setItemName(westItem.getItemName());
                violation.setMsgId("840004");
                violations.add(violation);
            }
        }

        if (violations.size() > 0) {
            return violations;
        }

        return null;
    }


    /**
     *
     * 更新病历处方违规内容
     * 先删除再重新生成
     */
    private void replacePrescriptionViolation(DtHealthDataOutpatientMedicalEntity medical,
                                              List<DtHealthDataWestPrescriptionEntity> prescriptions,
                                              List<DtInvsViolationManageEntity> violations) {
        for (DtHealthDataWestPrescriptionEntity prescription : prescriptions) {
            DtInvsViolationManageEntity w = new DtInvsViolationManageEntity();
            w.setInstitutionId(medical.getInstitutionId());
            w.setMedicalId(medical.getId());
            w.setPrescriptionId(prescription.getPrescriptionId());
            // 旧的消息队列状态更新成不显示
            List<String> targetIds = dtInvsViolationManageMapper.selectTargetIds(w);
            if (targetIds.size() > 0) {
                dtInvsMessageQueueMapper.updateQueueStatus(medical.getInstitutionId(), 401, 3, targetIds);
                // 旧的异常行为每日check更新成已删除
                List<String> illegalIds = dtInvsIllegalCheckDailyMapper.selectIllegalIds(medical.getInstitutionId(), 40, 401, targetIds);
                dtInvsIllegalCheckDailyMapper.updateCheckDailyStatus(medical.getInstitutionId(), 40, 401, targetIds);
                // 旧的机构异常行为申诉更新成已删除
                if (illegalIds.size() > 0) {
                    dtInvsIllegalAppealMapper.updateIllegalAppealStatus(illegalIds);
                }
            }
            // 旧的违规内容状态更新成已删除
            dtInvsViolationManageMapper.updateStatus(w);
        }
        // 新生成违规内容
        if (violations.size() > 0) {
            dtInvsViolationManageMapper.insertPrescriptionViolation(violations);
            // 新生成消息队列(用于首页地图展示)
            insertMessageQueue(medical, violations);
            // 新生成机构异常行为每日check
            List<DtInvsIllegalCheckDailyEntity> dailys = insertCheckDaily(medical, violations);
            // 生成新的机构异常行为申诉
            insertIllegalAppeal(dailys);
        }

    }

    /**
     *
     * 判断医师是否越级使用抗菌药物
     *
     */
    private DtInvsViolationManageEntity rightToAntibiosisGrade(DdDoctorEntity doctor, List<ClinicAuditItemModel> items) {
        DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();

        // 抗菌药物处方资格
        Integer antibiosisAuthority = doctor.getAntibiosisAuthority();
        if (antibiosisAuthority == null || antibiosisAuthority.intValue() < 1 ) {
            return null;
        }
        List<ClinicAuditItemModel> filterList = items.stream().filter(a -> a.getBaseDrug().getAntibiosisFlg() > 1).collect(Collectors.toList());
        if (filterList != null && filterList.size() > 0) {
            List<MaDataDictionaryEntity> antibiosisFlgList =  dataDictionaryService.getCodeList(DataDictionaryCons.CODE_ANTIBIOSIS_FLG);
            String param = "";
            for (ClinicAuditItemModel item : filterList) {
                MaInvsBaseDrug baseDrug = item.getBaseDrug();
                if (antibiosisAuthority.intValue() < baseDrug.getAntibiosisFlg().intValue()) {
                    DtHealthDataWestPrescriptionEntity westItem = item.getWestItem();
                    List<MaDataDictionaryEntity> flgList = antibiosisFlgList.stream().filter(a -> a.getValue().equals(baseDrug.getAntibiosisFlg().toString())).collect(Collectors.toList());
                    String name = getAntibiosisName(flgList, westItem, baseDrug);
                    if (CheckUtil.isEmpty(param)) {
                        param = name;
                    } else {
                        param = param + "、" + name;
                    }
                }
            }
            if (!CheckUtil.isEmpty(param)) {
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setDoctorName(doctor.getName());
                violation.setMsgId("820005");
                return violation;
            }
        }

        return null;
    }

    /**
     *
     * 判断限制使用性别
     *
     */
    private List<DtInvsViolationManageEntity> limitGender(List<ClinicAuditItemModel> items, Integer gender) {
        // 病历上患者性别没有填写时，不校验
        if (gender.intValue() == 0) {
            return null;
        }

        List<DtInvsViolationManageEntity> violations = new ArrayList<>();

        for (ClinicAuditItemModel item : items) {
            DtHealthDataWestPrescriptionEntity westItem = item.getWestItem();
            MaInvsBaseDrug baseDrug = item.getBaseDrug();
            Integer limitGender = baseDrug.getLimitGender();
            if (limitGender.intValue() == 0) {
                continue;
            }
            // 药品限制使用性别和患者性别不一致
            if (limitGender.intValue() != gender.intValue()) {
                String param = baseDrug.getLimitGenderTxt();
                DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setItemName(westItem.getItemName());
                violation.setMsgId("840005");
                violations.add(violation);
            }
        }

        if (violations.size() > 0) {
            return violations;
        }

        return null;
    }

    /**
     *
     * 判断老年患者禁用
     *
     */
    private List<DtInvsViolationManageEntity> oldForbid(List<ClinicAuditItemModel> items, Integer age) {
        // 病历上患者年龄没有填写或者年龄小于60岁时，不校验
        if (age == null || age.intValue() < 60) {
            return null;
        }

        List<DtInvsViolationManageEntity> violations = new ArrayList<>();

        for (ClinicAuditItemModel item : items) {
            DtHealthDataWestPrescriptionEntity westItem = item.getWestItem();
            MaInvsBaseDrug baseDrug = item.getBaseDrug();
            Integer oldForbid = baseDrug.getOldForbid();
            if (oldForbid.intValue() == 0) {
                continue;
            }
            // 老年患者禁用
            if (oldForbid.intValue() == 1) {
                String param = "老年患者禁用";
                DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setItemName(westItem.getItemName());
                violation.setMsgId("840008");
                violations.add(violation);
            }
        }

        if (violations.size() > 0) {
            return violations;
        }

        return null;
    }

    /**
     *
     * 判断儿童禁用
     *
     */
    private List<DtInvsViolationManageEntity> childForbid(List<ClinicAuditItemModel> items, Integer age) {
        // 病历上患者年龄没有填写或者年龄大于14岁时，不校验
        if (age == null || age.intValue() > 14) {
            return null;
        }

        List<DtInvsViolationManageEntity> violations = new ArrayList<>();

        for (ClinicAuditItemModel item : items) {
            DtHealthDataWestPrescriptionEntity westItem = item.getWestItem();
            MaInvsBaseDrug baseDrug = item.getBaseDrug();
            Integer childForbid = baseDrug.getChildForbid();
            if (childForbid.intValue() == 0) {
                continue;
            }
            // 儿童禁用
            if (childForbid.intValue() == 1) {
                String param = "儿童禁用";
                DtInvsViolationManageEntity violation = new DtInvsViolationManageEntity();
                violation.setParams(param);
                violation.setPrescriptionId(items.get(0).getWestItem().getPrescriptionId());
                violation.setItemName(westItem.getItemName());
                violation.setMsgId("840007");
                violations.add(violation);
            }
        }

        if (violations.size() > 0) {
            return violations;
        }

        return null;
    }

    /**
     *
     * 取得包含级别的抗菌药物名称
     *
     */
    private String getAntibiosisName(List<MaDataDictionaryEntity> flgList
            , DtHealthDataWestPrescriptionEntity westItem
            , MaInvsBaseDrug baseDrug) {
        String name = "";
        if (flgList != null && flgList.size() > 0) {
            name = westItem.getItemName() + "(" + flgList.get(0).getAbbreviation() + ")"; // 药物名+(抗菌药物等级)
        } else {
            throw new RuntimeException("ma_data_dictionary表中无抗菌药物等级["+baseDrug.getAntibiosisFlg()+"]数据，请设置！");
        }
        return name;
    }

    /**
     *
     * 复制多条处方违规内容
     *
     */
    private List<DtInvsViolationManageEntity> copys(List<DtInvsViolationManageEntity> origs) {
        List<DtInvsViolationManageEntity> dests = new ArrayList<>();
        for (DtInvsViolationManageEntity orig : origs) {
            dests.add(copy(orig));
        }
        return dests;
    }

}
